
/**
 * Copyright 2009 cestum.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
package org.waveprotocol.wave.model.wave.data.impl {
import org.goverla.collections.ArrayList;
import org.goverla.collections.HashMap;
import org.waveprotocol.wave.model.document.operation.BufferedDocOp;
import org.waveprotocol.wave.model.document.operation.algorithm.Composer;
import org.waveprotocol.wave.model.document.operation.impl.DocOpBuffer;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.model.operation.OpComparators;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.WaveletData;

/**
 * Defines the abstract data type used to describe the content of a wavelet.
 * same as wave-protocol implemenation
 *
*/
public class WaveletDataImpl implements WaveletData {

  /** A document (operation) with no contents. */
  private static var EMPTY_DOC_OP:BufferedDocOp= new DocOpBuffer().finish();

  /** Id of the wave to which this wavelet belongs. */
  private var waveId:WaveId;

  /** The identifier of this wavelet. */
  private var waveletId:WaveletId;

  /** The list of participants in this wavelet. */
  private var participants:ArrayList;

  /** The set of documents in this wave, indexed by their identifier. */
  private var documents:HashMap;

  /**
   * Creates a new wavelet. When constructed the hashedVersion will be for
   * version 0 of the wavelet, it must be updated using setHashedVersion
   * by the owner of this object.
   */
  public function WaveletDataImpl(waveId:WaveId, id:WaveletId) {
    if (id == null) {
      throw new Error("id cannot be null");
    } else if (waveId == null) {
      throw new Error("wave id cannot be null");
    }

    this.waveletId = id;
    this.waveId = waveId;
    this.participants = new ArrayList();
    this.documents = new HashMap();
  }

  private function getOrCreateDocument(documentId:String):BufferedDocOp {
    var doc:BufferedDocOp= BufferedDocOp(documents.getItem(documentId));
    if (doc == null) {
      doc = EMPTY_DOC_OP;
      documents.addItem(documentId, doc);
    }
    return doc;
  }

   public function getDocuments():HashMap {
	   return documents;
  }
  
  public function getParticipants():ArrayList {
	  return participants;
  }
  
  public function getWaveletName():WaveletName {
    return WaveletName.of(waveId, waveletId);
  }
  
  public function addParticipant(p:ParticipantId):Boolean {
    if (hasParticipant(p))
		return false;
	else { 
		participants.addItem(p);
		return true;
	}
  }

  private function hasParticipant(p:ParticipantId):Boolean {
	  for (var i:int=0; i<participants.length; i++) {
		  if(ParticipantId(participants.getItemAt(i)).getAddress() == p.getAddress()) {
			  return true;
		  } 
	  }
	  return false;
  } 
  
  public function removeParticipant(p:ParticipantId):Boolean {
	  var idx:int = -1;
	  for (var i:int=0; i<participants.length; i++) {
		  if(ParticipantId(participants.getItemAt(i)).getAddress() == p.getAddress()) {
			  idx = i;
			  break;
		  } 
	  }
    return idx != -1 ? participants.removeItemAt(idx) : true;
  }

  
  public function modifyDocument(documentId:String, operation:BufferedDocOp):Boolean {
    var newDoc:BufferedDocOp= Composer.compose2(getOrCreateDocument(documentId), operation);
    if (OpComparators.SYNTACTIC_IDENTITY.equal(newDoc, EMPTY_DOC_OP)) {
      documents.removeItemAt(documentId);
    } else {
      documents.addItem(documentId, newDoc);
    }
    return true;
  }

  
  public function toString():String {
    return "Wavelet State = " + waveId + " " + waveletId + " " + documents;
  }
}
}